package com.korustar.autumnal;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver;
import org.springframework.beans.factory.xml.NamespaceHandler;
import org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler;
import org.springframework.beans.factory.xml.UtilNamespaceHandler;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Loads bean registry from an application context file
 * 
 * @author amir
 */
public class XmlBeanInterpretation {
	private static final String SPRINGFRAMEWORK_SCHEMA_P = "http://www.springframework.org/schema/p";
	private static final String SPRINGFRAMEWORK_SCHEMA_UTIL = "http://www.springframework.org/schema/util";
	private static Logger LOGGER = LoggerFactory.getLogger( XmlBeanInterpretation.class );
	
	public static BeanDefinitionRegistry getBeanRegistry(String xml) {
		Resource resource= new ByteArrayResource(xml.getBytes());
		return getBeanRegistry(resource);
	}

	public static BeanDefinitionRegistry getBeanRegistry(File file) {
		FileSystemResource fileSystemResource = new FileSystemResource(file);
		return getBeanRegistry(fileSystemResource);
	}
	
	public static BeanDefinitionRegistry getBeanRegistry(Resource resource) {
		
		XmlBeanDefinitionReader reader;
		DefaultListableBeanFactory registry= new DefaultListableBeanFactory();
		reader = new XmlBeanDefinitionReader(registry);
		reader.setNamespaceAware(true);
		reader.setValidating(true);
		
		//strange behaviour forcing this override...
		DefaultNamespaceHandlerResolver namespaceHandlerResolver= new DefaultNamespaceHandlerResolver() {
			@Override
			public NamespaceHandler resolve(String namespaceUri) {
				
				 if(SPRINGFRAMEWORK_SCHEMA_P.equals(namespaceUri)) {
					 LOGGER.debug("manually setting handler for 'p' namespace");
					 return new SimplePropertyNamespaceHandler();
				 }
				 if(SPRINGFRAMEWORK_SCHEMA_UTIL.equals(namespaceUri)) {
					 LOGGER.debug("manually setting handler for 'util' namespace");
					 UtilNamespaceHandler namespaceHandler= new UtilNamespaceHandler();
					 namespaceHandler.init();
					 return namespaceHandler;
				 }
				 NamespaceHandler resolve = super.resolve(namespaceUri);
				 return resolve;
			}
		};
		reader.setNamespaceHandlerResolver(namespaceHandlerResolver);
		reader.loadBeanDefinitions(resource);
		
		return registry;
	}
	/*
	public static BeanDefinitionRegistry getRegistry(String xml) {
		Resource resource= new ByteArrayResource(xml.getBytes());
		XmlBeanFactory registry= new XmlBeanFactory(resource);
		//registry.g
		List<BeanPostProcessor> beanPostProcessors = registry.getBeanPostProcessors();
		for(BeanPostProcessor b : beanPostProcessors) {
			LOGGER.info("post processor: {}",b.getClass());
		}
		return registry;
	}*/
	
	public static NodeList getBeanNodes(Document doc) throws XPathExpressionException {
		String xpathLowHangers = "//bean";
		NodeList nodes = runXpathQuery(doc, xpathLowHangers);
		return nodes;
	}

	private static NodeList runXpathQuery(Document doc, String xpathExpression)
			throws XPathExpressionException {
		XPathFactory xfactory = XPathFactory.newInstance();
		XPath xpath = xfactory.newXPath();
		XPathExpression expr = xpath.compile(xpathExpression);
		Object result = expr.evaluate(doc, XPathConstants.NODESET);
		NodeList nodes = (NodeList) result;
		return nodes;
	}
	
	public static Document buildDocument(String xml)
			throws ParserConfigurationException, SAXException, IOException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true); // never forget this!
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse(new InputSource(new StringReader(xml)));
		return doc;
	}

	
}
